package com.tbit.uqbike.webmanager.controller;

import cn.hutool.core.util.StrUtil;
import com.tbit.common.constant.OperationPlatform;
import com.tbit.common.entity.UserOpLog;
import com.tbit.uqbike.annos.OperateLog;
import com.tbit.uqbike.constant.UserConstant;
import com.tbit.common.constant.MethodEnum;
import com.tbit.common.constant.ModuleEnum;
import com.tbit.uqbike.enums.SystemCodeEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.User;
import com.tbit.uqbike.object.pojo.UserBlackList;
import com.tbit.uqbike.object.pojo.vo.BatchOperationMsgVO;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.uqbike.object.view.JsonResult;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.service.business.AccountService;
import com.tbit.uqbike.service.business.BlackListLogService;
import com.tbit.uqbike.service.business.UserBlackListService;
import com.tbit.uqbike.service.business.UserService;
import com.tbit.uqbike.webmanager.business.user_op_log.service.UserOpLogService;
import com.tbit.uqbike.webmanager.util.Assert;
import com.tbit.uqbike.webmanager.util.excel.ExcelUtil;
import com.tbit.utils.DateTimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户黑名单
 *
 * @author Leon
 * 2017年2月24日 下午5:51:05
 */
@Slf4j
@Validated
@RestController
@RequestMapping(value = "/userBlackList", produces = BaseController.MEDIA_JSON_UTF8)
public class UserBlackListController extends BaseController {
    @Autowired
    private UserService userService;
    @Autowired
    private UserBlackListService userBlackListService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private BlackListLogService blackListLogService;
    @Autowired
    private UserOpLogService userOpLogService;


    /**
     * @param userBlackList 用户黑名单对象
     * @param endTime       到期时间
     * @param isSend        消息推送开关 1开启，0关闭
     * @param blockType     拉黑类型，0为电话号码拉黑 1为身份证拉黑 2手机号为批量拉黑 3为身份证批量拉黑
     * @param isBlock       是否要进行身份证拉黑，1是，0否
     * @param phones        手机号
     * @param request       请求
     * @return
     */
    @RequestMapping("/add")
    @OperateLog(module = ModuleEnum.USERBLACK, methods = MethodEnum.USERBLACK_ADD)
    public JsonResult add(UserBlackList userBlackList, Long endTime, Integer isSend, Integer blockType,
                          Integer isBlock, String phones, String idNo, String idNos, HttpServletRequest request,
                          Integer actionType
    ) {
        // 非空校验
        Assert.notNull(endTime, "ver.expireTime.notNull");
        Assert.hasLength(userBlackList.getRemark(), "ver.remark.notNull");
        Assert.notNull(userBlackList.getAccountId(), "ver.accountId.notNull");
        if (StrUtil.isNotEmpty(userBlackList.getPhone()) && userBlackList.getPhone().length() > 50) {
            throw new BaseException("手机号长度过长");
        } else if (StrUtil.isNotEmpty(userBlackList.getRemark()) && userBlackList.getRemark().length() > 255) {
            throw new BaseException("备注长度过长");
        }
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        // 获取用户信息
        LoginInfo loginInfo = getLogin(request);
        Integer accountId = userBlackList.getAccountId();
        /*if (loginInfo.type.equals(UserConstant.USER_ADMIN)) {
            accountId = userBlackList.getAccountId();
        } else {
            if (!loginInfo.type.equals(UserConstant.USER_BRAND)) {
                throw new BaseException(SystemCodeEnum.NO_PRIVILEGE);
            }
            accountId = loginInfo.id;
        }*/
        LinkedList<String> successList = new LinkedList<>();
        // 加入黑名单
        switch (blockType) {
            // 电话号码拉黑
            case 0:
                setUserBlackListByPhone(userBlackList, isBlock, accountId, endTime, isSend, loginInfo);
                successList.add(userBlackList.getPhone());
                batchOperationMsgVO.setSuccessList(successList);
                break;
            // 身份证号码拉黑
            case 1:
                setUserBlackListByIdNo(userBlackList, accountId, endTime, isSend, loginInfo);
                successList.add(userBlackList.getIdNo());
                batchOperationMsgVO.setSuccessList(successList);
                break;
            // 手机号码批量拉黑，
            case 2:
                batchOperationMsgVO = userBlackListService.setUserBlackListByPhoneBatchV2(userBlackList, accountId, phones, endTime, loginInfo, actionType);
//                batchOperationMsgVO = setUserBlackListByPhoneBatch(userBlackList, accountId, phones, endTime, loginInfo, actionType);
                break;
            // 身份证号码批量拉黑，
            case 3:
                batchOperationMsgVO = setUserBlackListByIdNoBatch(userBlackList, idNos, accountId, endTime, loginInfo);
                break;
            // 其他情况返回错误
            default:
                throw new BaseException("请选择正确的拉黑类型！");
        }
        return JsonResult.ok(batchOperationMsgVO);
    }


    /* 删除 */
    @RequestMapping("/del")
    @OperateLog(module = ModuleEnum.USERBLACK, methods = MethodEnum.USERBLACK_DEL)
    public JsonResult del(Integer userId, Integer blockType, String idNo, String phone, String delAll, HttpServletRequest request) {
        /* 校验 */
        Assert.notNull(userId, "ver.userId.notNull");

//        String idNo1 = getIdNo(userId, blockType, idNo, delAll);
        if (StringUtils.isNotBlank(idNo)) {
            userBlackListService.del(null, idNo, null);
        } else {
            userBlackListService.del(userId, null, phone);
        }
        return JsonResult.ok();
    }

    /* 分页查询 */
    @RequestMapping("/queryPage")
    public JsonResult queryPage(@RequestParam(defaultValue = "10") Integer rowCount,
                                @RequestParam(defaultValue = "1") Integer pageNO,
                                String phone, String idNo, Integer accountId, Integer blockType,
                                HttpServletRequest request) {

        LoginInfo loginInfo = getLogin(request);

        // 获取账户id
        if (loginInfo.type.equals(UserConstant.USER_BRAND)) {
            accountId = loginInfo.id;
        } else if (loginInfo.type.equals(UserConstant.USER_FRANCHISEE) || loginInfo.type.equals(UserConstant.USER_AGENT)) {
            accountId = accountService.getBrandId(loginInfo.id);
        } else {
            Assert.notNull(accountId, "ver.accountId.notNull");
        }

        // 获取查询结果
        List<UserBlackList> suggestions = userBlackListService.queryPage(accountId, phone, idNo, blockType, rowCount, pageNO);

        // 获取总数
        Integer total = userBlackListService.queryCount(accountId, phone, idNo, blockType);
        return JsonResult.ok(suggestions, total);
    }

    /**
     * 黑名单记录导出
     *
     * @param phone     。
     * @param idNo      。
     * @param accountId 。
     * @param blockType 。
     * @return 。
     */
    @GetMapping("/export")
    public Result<String> export(String phone, String idNo, @NotNull(message = "请选择品牌") Integer accountId, Integer blockType) {
        List<UserBlackList> blockList = userBlackListService.queryPage(accountId, phone, idNo, blockType, 20000, 1);
        ExcelUtil<UserBlackList> excel = new ExcelUtil<>(UserBlackList.class);
        JsonResult jsonResult = excel.exportExcel(blockList, "黑名单记录记录");
        return Result.success(jsonResult.getData().toString());
    }

    @RequestMapping("/page")
    public JsonResult page(@RequestParam(defaultValue = "10") Integer rowCount,
                           @RequestParam(defaultValue = "1") Integer pageNO,
                           String phone, Integer accountId,
                           HttpServletRequest request) {

        return JsonResult.ok();
    }

    private String getIdNo(Integer userId, Integer blockType, String idNo, String delAll) {
        if (blockType == 1) {
            Assert.notNull(idNo, "ver.idNo.notNull");
            return idNo;
        }
        delAll = "true";
        /**删除电话号码同时删除同一个身份证的其他电话号码*/
        if ("true".equals(delAll)) {
            UserBlackList userBlackList = userBlackListService.getByUserId(userId);
            if (userBlackList != null) {
                return userBlackList.getIdNo();
            }
        }
        return null;
    }


    /**
     * 通过电话号码拉黑用户
     *
     * @param userBlackList 用户黑名单对象
     * @param isBlock       手机号拉黑同时是否同时拉黑身份证，0否 ，1是
     * @param accountId     区域id
     * @param endTime       黑名单失效时间
     * @param isSend        是否发送消息：0是不发送，1是发送
     * @param loginInfo     用户登录信息
     */
    private void setUserBlackListByPhone(UserBlackList userBlackList,
                                         Integer isBlock,
                                         Integer accountId,
                                         Long endTime,
                                         Integer isSend,
                                         LoginInfo loginInfo) {

        Assert.notNull(isSend, "ver.isSend.notNull");
        Assert.hasLength(userBlackList.getPhone(), "ver.phone.notNull");
        List<User> users = userService.getByAccountIdAndPhone(accountId, userBlackList.getPhone());
        //不存在预先拉黑
        if (CollectionUtils.isEmpty(users)) {
            User user = createUser(accountId, userBlackList.getPhone());
            users.add(user);
            //预先拉黑没有身份证,而且不适合发送短信。
            isBlock = 0;
        } else {
            // 校验是否已经在黑名单
            UserBlackList userBlackListDB = userBlackListService.getByUserId(users.get(0).getUserId());
            List<UserBlackList> listByIdNo = userBlackListService.getByIdNo(userBlackList.getAccountId(), users.get(0).getIdNO());
            if (userBlackListDB != null) {
                throw new BaseException(SystemCodeEnum.USER_HAVE_EXIST);
            }
            if (listByIdNo != null && listByIdNo.size() > 0) {
                throw new BaseException("身份证号码已经被拉黑");
            }
        }

        // 电话号码加入黑名单且把这个身份证其他电话号码都拉黑
        if (isBlock == 1) {
            for (User user : users) {
                List<User> userList = userService.getByAccountAndIdNO(accountId, user.getIdNO());
                List<UserOpLog> opLogs = new ArrayList<>();
                // 系统中可以查询到该用户
                if (userList.size() > 0) {
                    for (User userIdNo : userList) {
                        userBlackList.setPhone(userIdNo.getPhone());
                        userBlackList.setAccountId(accountId);
                        userBlackList.setUserId(userIdNo.getUserId());
                        userBlackList.setAddTime(new Date());
                        userBlackList.setIdNo(userIdNo.getIdNO());
                        if (endTime != null) {
                            userBlackList.setExpireTime(new Date(endTime));
                        }
                        userBlackListService.insert(userBlackList, isSend);
                        blackListLogService.insert(loginInfo, userBlackList);

                        // 添加用户操作日志
                        opLogs.add(UserOpLog.builder()
                                .accountId(userIdNo.getAccountId())
                                .opUser(loginInfo.getName())
                                .opUserPhone(loginInfo.getPhone())
                                .targetUser(userIdNo.getName())
                                .targetUserPhone(userIdNo.getPhone())
                                .operation("用户账号管理")
                                .opType("拉入黑名单")
                                .opPlatform(OperationPlatform.MANAGER.code)
                                .opTime(LocalDateTime.now())
                                .result(true)
                                .build());
                    }
                    userOpLogService.insertBatch(opLogs);
                } else {
                    throw new BaseException("用户未实名，级联拉黑身份证失败");
                }
            }
        } else if (isBlock == 0) {
            //非级联拉黑
            userBlackList.setAccountId(accountId);
            userBlackList.setUserId(users.get(0).getUserId());
            userBlackList.setAddTime(new Date());
            //userBlackList.setIdNo(users.get(0).getIdNO());
            if (endTime != null) {
                userBlackList.setExpireTime(new Date(endTime));
            }
            userBlackListService.insert(userBlackList, isSend);
            blackListLogService.insert(loginInfo, userBlackList);
        }
    }

    /**
     * 通过身份证号码拉黑用户
     *
     * @param userBlackList 用户黑名单对象
     * @param accountId     区域id
     * @param endTime       黑名单失效时间
     * @param isSend        是否发送消息：0是不发送，1是发送
     * @param loginInfo     用户登录信息
     *                      ..........................................................
     */
    private void setUserBlackListByIdNo(UserBlackList userBlackList,
                                        Integer accountId,
                                        Long endTime,
                                        Integer isSend,
                                        LoginInfo loginInfo) {

        Assert.notNull(isSend, "ver.isSend.notNull");
        Assert.hasLength(userBlackList.getIdNo(), "ver.idNo.notNull");
        /**根据身份证查出用户*/
        List<User> users1 = userService.getByAccountIdAndIdNo(accountId, userBlackList.getIdNo());
        if (users1 == null || users1.size() < 1) {
            throw new BaseException(SystemCodeEnum.USER_NOT_EXIT);
        }
        /**判断是否已经存在黑名单中*/
        List<UserBlackList> userBlackListDB1 = userBlackListService.getByIdNo(accountId, userBlackList.getIdNo());
        if (userBlackListDB1 != null && userBlackListDB1.size() > 0) {
            throw new BaseException(SystemCodeEnum.USER_HAVE_EXIST);
        }
        List<UserOpLog> opLogs = new ArrayList<>();
        for (User user : users1) {
            userBlackList.setAccountId(accountId);
            userBlackList.setUserId(user.getUserId());
            userBlackList.setAddTime(new Date());
            userBlackList.setIdNo(userBlackList.getIdNo());
            userBlackList.setPhone(user.getPhone());
            if (endTime != null) {
                userBlackList.setExpireTime(new Date(endTime));
            }
            userBlackListService.insert(userBlackList, isSend);
            blackListLogService.insert(loginInfo, userBlackList);

            // 添加用户操作日志
            opLogs.add(UserOpLog.builder()
                    .accountId(user.getAccountId())
                    .opUser(loginInfo.getName())
                    .opUserPhone(loginInfo.getPhone())
                    .targetUser(user.getName())
                    .targetUserPhone(user.getPhone())
                    .operation("用户账号管理")
                    .opType("拉入黑名单")
                    .opPlatform(OperationPlatform.MANAGER.code)
                    .opTime(LocalDateTime.now())
                    .result(true)
                    .build());
        }
        userOpLogService.insertBatch(opLogs);
    }

    /**
     * 通过批量添加手机号拉黑用户
     *
     * @param userBlackList 用户黑名单对象
     * @param accountId     区域id
     * @param phones        手机号码字符串，中间以 , 拼接
     * @param endTime       黑名单失效时间
     * @param loginInfo     用户登录信息
     * @param actionType    null/0 = 检测  1-忽略添加  2-强制更新
     */
    private BatchOperationMsgVO<String> setUserBlackListByPhoneBatch(UserBlackList userBlackList,
                                                                     Integer accountId, String phones,
                                                                     Long endTime, LoginInfo loginInfo, Integer actionType) {
        Assert.notNull(phones, "ver.phone.notNull");
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        List<String> successList = new LinkedList<>();
        List<String> failList = new LinkedList<>();

        String[] phoneList = phones.split(",");
        Map<String, User> userMap = userService.mapByUserPhone(new HashSet<>(Arrays.asList(phoneList)), accountId);
        //检测已存在的用户
        Map<String, UserBlackList> existBlockUserMap = userMap.values().stream()
                .map(User::getUserId)
                .map(userBlackListService::getByUserId)
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(UserBlackList::getPhone, u -> u, (u1, u2) -> u1));
        if (MapUtils.isNotEmpty(existBlockUserMap) && (actionType == null || actionType == 0)) {
            batchOperationMsgVO.setFailList(existBlockUserMap.values().stream().map(UserBlackList::getPhone).collect(Collectors.toList()));
            return batchOperationMsgVO;
        }
        //收集要添加的用户黑名单
        List<User> insertBlockList = new ArrayList<>();
        List<UserOpLog> opLogs = new ArrayList<>();
        for (String phone : phoneList) {
            User user = userMap.get(phone);
            if (user == null) {
                user = createUser(accountId, phone);
            } else {
                if (actionType != null && actionType == 1) {
                    continue;
                }
                UserBlackList existsBlockUser = existBlockUserMap.get(phone);
                if (existsBlockUser != null) {
                    userBlackListService.del(userBlackList.getUserId(), null, phone);
                }
            }
            successList.add(phone);
            insertBlockList.add(user);
            // 添加用户操作日志
            opLogs.add(UserOpLog.builder()
                    .accountId(user.getAccountId())
                    .opUser(loginInfo.getName())
                    .opUserPhone(loginInfo.getPhone())
                    .targetUser(user.getName())
                    .targetUserPhone(user.getPhone())
                    .operation("用户账号管理")
                    .opType("拉入黑名单")
                    .opPlatform(OperationPlatform.MANAGER.code)
                    .opTime(LocalDateTime.now())
                    .result(true)
                    .build());
        }
        userOpLogService.insertBatch(opLogs);

        insertBlockList.forEach(x -> {
            userBlackList.setAccountId(accountId);
            userBlackList.setUserId(x.getUserId());
            userBlackList.setAddTime(new Date());
            if (endTime != null) {
                userBlackList.setExpireTime(new Date(endTime));
            }
            userBlackList.setPhone(x.getPhone());
            userBlackListService.insert(userBlackList, 1);
            blackListLogService.insert(loginInfo, userBlackList);
        });
        batchOperationMsgVO.setSuccessList(successList).setFailList(failList);
        return batchOperationMsgVO;
    }

    private User createUser(Integer accountId, String phone) {
        User user = new User();
        user.setAccountId(accountId);
        user.setBirthDay(DateTimeUtil.getNowTimeyyyyMMdd());
        user.setPhone(phone);
        user.setEmail("");
        user.setRemark("预拉黑添加用户");
        user.setSex("");
        user.setUpdateTime(DateTimeUtil.getNowTime());
        user.setJoinTime(DateTimeUtil.getNowTime());
        user.setCountry("86");
        userService.insert(user);
        return user;
    }

    /**
     * 通过批量添加身份证号码拉黑用户
     *
     * @param userBlackList 用户黑名单对象
     * @param idNos         身份证号码字符串，身份证号码之间以 , 拼接
     * @param endTime       黑名单失效时间
     * @param loginInfo     用户登录信息
     */
    private BatchOperationMsgVO<String> setUserBlackListByIdNoBatch(UserBlackList userBlackList,
                                                                    String idNos,
                                                                    Integer accountId,
                                                                    Long endTime,
                                                                    LoginInfo loginInfo) {
        Assert.notNull(idNos, "身份证号码不能为空");
        List<String> idNoList = Arrays.asList(idNos.split(","));
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        List<String> successList = new LinkedList<>();
        for (String num : idNoList) {
            if (num.trim().isEmpty()) {
                continue;
            }
            List<User> users3 = userService.getByAccountIdAndIdNo(accountId, num);
            successList.add(num);
            // 如果用户表里不存在这个用户，直接添加
            if (users3.isEmpty()) {
                userBlackList.setAccountId(accountId);
                userBlackList.setUserId(null);
                userBlackList.setAddTime(new Date());
                if (endTime != null) {
                    userBlackList.setExpireTime(new Date(endTime));
                }
                userBlackList.setIdNo(num);
                userBlackList.setPhone(null);
                List<UserBlackList> hasIdNo = userBlackListService.getByIdNo(userBlackList.getAccountId(), num);
                if (hasIdNo != null && hasIdNo.size() > 0) {
                    userBlackListService.update(userBlackList);
                } else {
                    userBlackListService.insert(userBlackList, 0);
                }
                blackListLogService.insert(loginInfo, userBlackList);
                continue;
            }
            // 如果黑名单里存在这个用户，覆盖原来记录
            for (User user : users3) {
                UserBlackList userBlackListDB3 = userBlackListService.getByUserId(user.getUserId());
                if (userBlackListDB3 != null) {
                    userBlackListService.del(userBlackList.getUserId(), num, null);
                }
            }
            List<UserOpLog> opLogs = new ArrayList<>();
            for (User user : users3) {
                userBlackList.setAccountId(accountId);
                userBlackList.setUserId(user.getUserId());
                userBlackList.setAddTime(new Date());
                userBlackList.setPhone(user.getPhone());
                if (endTime != null) {
                    userBlackList.setExpireTime(new Date(endTime));
                }
                userBlackList.setIdNo(num);
                userBlackListService.insert(userBlackList, 0);
                blackListLogService.insert(loginInfo, userBlackList);
                // 添加用户操作日志
                opLogs.add(UserOpLog.builder()
                        .accountId(user.getAccountId())
                        .opUser(loginInfo.getName())
                        .opUserPhone(loginInfo.getPhone())
                        .targetUser(user.getName())
                        .targetUserPhone(user.getPhone())
                        .operation("用户账号管理")
                        .opType("拉入黑名单")
                        .opPlatform(OperationPlatform.MANAGER.code)
                        .opTime(LocalDateTime.now())
                        .result(true)
                        .build());
            }
            userOpLogService.insertBatch(opLogs);

        }
        batchOperationMsgVO.setSuccessList(successList);
        return batchOperationMsgVO;
    }

    /**
     * 修改黑名单过期时间
     *
     * @param userId     用户id
     * @param expireTime 到期时间
     */
    @PostMapping("/updateByUserId")
    public Result<String> updateByUserId(@NotNull Integer userId, @NotNull Date expireTime) {

        UserBlackList userBlackListUpdate = new UserBlackList();
        userBlackListUpdate.setUserId(userId);
        userBlackListUpdate.setExpireTime(expireTime);
        userBlackListService.updateEntityByUserId(userBlackListUpdate);

        return Result.success();
    }

}